import * as THREE from 'three';

export function createCameraManager(gameWindow) {
  const DEG2RAD = Math.PI / 180;

  const LEFT_MOUSE_BUTTON = 0;
  const MIDDLE_MOUSE_BUTTON = 4;
  const RIGHT_MOUSE_BUTTON = 2;

  // 半径和海拔
  const MIN_CAMERA_RADIUS = 10;
  const MAX_CAMERA_RADIUS = 100;
  const MIN_CAMERA_ELEVATION = 10;
  const MAX_CAMERA_ELEVATION = 90;

  // 灵敏度
  const AZIMUTH_SENSITIVITY = .2;
  const ELEVATION_SENSITIVITY = .2;
  const ROTATION_SENSITIVITY = .5;
  const ZOOM_SENSITIVITY = .01;
  const PAN_SENSITIVITY = -.01;

  const Y_AXIS = new THREE.Vector3(0, 1, 0);

  const camera = new THREE.PerspectiveCamera(45, gameWindow.offsetWidth / gameWindow.offsetHeight, .1, 1000);
  const cameraOrigin = new THREE.Vector3(6, 0, 6);
  const cameraProps = {
    radius: 30/* (MIN_CAMERA_RADIUS + MAX_CAMERA_RADIUS) * .5 */,
    azimuth: 135,
    elevation: 45,
  };
  const isMouseDown = {
    [LEFT_MOUSE_BUTTON]: false,
    [MIDDLE_MOUSE_BUTTON]: false,
    [RIGHT_MOUSE_BUTTON]: false,
  };
  const preMouse = { x: 0, y: 0 };
  updateCameraPosition();

  /**
   * @param {MouseEvent} event 
   */
  function handleMouseDown(event) {
    isMouseDown[event.button] = true;
  }

  /**
   * @param {MouseEvent} event 
   */
  function handleMouseUp(event) {
    isMouseDown[event.button] = false;
  }

  /**
   * @param {MouseEvent} event 
   */
  function handleMouseMove(event) {
    const delta = {
      x: event.clientX - preMouse.x,
      y: event.clientY - preMouse.y,
    };
    // 摄像机旋转
    if (isMouseDown[LEFT_MOUSE_BUTTON]) {
      cameraProps.azimuth += -(delta.x) * ROTATION_SENSITIVITY;
      cameraProps.elevation += (delta.y) * ROTATION_SENSITIVITY;
      cameraProps.elevation = R.clamp(MIN_CAMERA_ELEVATION, MAX_CAMERA_ELEVATION, cameraProps.elevation);
      updateCameraPosition();
    }

    // 摄像机平移
    if (isMouseDown[MIDDLE_MOUSE_BUTTON]) {
      const forward = new THREE.Vector3(0, 0, 1).applyAxisAngle(Y_AXIS, cameraProps.azimuth * Math.PI * 180);
      const left = new THREE.Vector3(1, 0, 0).applyAxisAngle(Y_AXIS, cameraProps.azimuth * Math.PI * 180);
      cameraOrigin.add(forward.multiplyScalar(PAN_SENSITIVITY * delta.y));
      cameraOrigin.add(left.multiplyScalar(PAN_SENSITIVITY * delta.x));
      updateCameraPosition();
    }

    // 摄像机变焦
    if (isMouseDown[RIGHT_MOUSE_BUTTON]) {
      cameraProps.radius += (delta.y) * ZOOM_SENSITIVITY;
      cameraProps.radius = R.clamp(MIN_CAMERA_RADIUS, MAX_CAMERA_RADIUS, cameraProps.radius);
      updateCameraPosition();
    }

    preMouse.x = event.clientX;
    preMouse.y = event.clientY;
  }

  function updateCameraPosition() {
    camera.position.x = cameraProps.radius * Math.sin(cameraProps.azimuth * DEG2RAD) * Math.cos(cameraProps.elevation * DEG2RAD);
    camera.position.y = cameraProps.radius * Math.sin(cameraProps.elevation * DEG2RAD);
    camera.position.z = cameraProps.radius * Math.cos(cameraProps.azimuth * DEG2RAD) * Math.cos(cameraProps.elevation * DEG2RAD);
    camera.position.add(cameraOrigin);
    camera.lookAt(cameraOrigin);
    camera.updateMatrix();
  }

  return {
    camera,
    handleMouseDown,
    handleMouseUp,
    handleMouseMove,
  }
}